package com.situ.company.web220111.util;

import java.lang.reflect.Field;
import java.sql.*;
import java.util.*;

// 工具类
// 工具类里绝大多数都是静态的方法
// 这样就可以直接使用工具类调用想要的方法就可以了
// 加上final，这个类不能被继承
// 构造方法私有化，这样这个类不能被实例化，只能通过(.)的方式来调用
public final class JDBCUtil { // DBTool

	private JDBCUtil() {
	}

	// 从属性配置文件中读取属性值/work1130/src/jdbc.properties
	private static ResourceBundle rb = ResourceBundle.getBundle("jdbc");
	private static String driver = rb.getString("driver");
	private static String url = rb.getString("url");
	private static String user = rb.getString("user");
	private static String pass = rb.getString("pass");

	// 执行一次就可以  so 使用静态代码块
	static {
		try {
			Class.forName(driver);
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
	}

	public static Connection getConnection1() throws SQLException {
		return DriverManager.getConnection(url, user, pass);
	}


	// try catch 写法
	public static Connection getConnection() {
		try {
			return DriverManager.getConnection(url, user, pass);
		} catch (SQLException e) {
			e.printStackTrace();
		}
		return null;
	}

	/**
	 * 执行DML语句
	 * @param sql
	 * @param values
	 * @return String
	 */
	public static String update(String sql, Object... values){  // 	不定参数
		return update(sql, Arrays.asList(values));
	}
	// 数组中元素类型是引用类型 -> asList返回的list中元素就是数组中的元素
	// 数组中元素类型是基本数据类型 -> asList返回的list中元素只有一个，即传入进来的这个数组

	/**
	 * 执行DML语句
	 * @param sql
	 * @param values
	 * @return String
	 */
	public static String update(String sql, List<Object> values){
		Connection conn = null;
		PreparedStatement ps = null;
		try {
			conn = getConnection();
			ps = conn.prepareStatement(sql);
			for (int i = 0;i<values.size();i++)
				ps.setObject(i+1,values.get(i));
			return ps.executeUpdate()+"";
		} catch (SQLException e) {
			e.printStackTrace();
		}finally {
			close(conn,ps);
		}
		return null;
	}

	/**
	 *
	 * @param sql 即将执行的sql语句
	 * @param values  执行的sql语句中的数据
	 * @param tClass  即将反射得到的实体类的类的描述
	 * @param fields  映射关系 key=属性名 value = 字段名
	 * @param <T>  返回集合中的元素类型（即表对应的实体类）
	 * @return
	 */
	public static <T> List<T> querylist(String sql,List<Object> values,Class<T> tClass,Map<String,String> fields){ // class:用类的描述传递泛型
		Connection conn=null;
		PreparedStatement ps = null;
		ResultSet rs = null;
		List<T> result = new ArrayList<T>();

		try {
			conn = getConnection();
			ps = conn.prepareStatement(sql);
			for (int i = 0;i< values.size();i++)
				ps.setObject(i+1,values.get(i));
			rs = ps.executeQuery();
			while (rs.next()){
				T model = tClass.newInstance(); // 用反射得到T的对象
				for (Map.Entry<String,String> entry:fields.entrySet()){
					Field field = tClass.getDeclaredField(entry.getKey()); // 根据属性名反射出对应的反射对象
					field.setAccessible(true);
					field.set(model,rs.getObject(entry.getValue()));
				}
				result.add(model);
			}
		} catch (SQLException e) {
			e.printStackTrace();
		} catch (InstantiationException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (NoSuchFieldException e) {
			e.printStackTrace();
		} finally {
			close(conn,ps,rs);
		}
		return result;
	}

	/**
	 * 第一次重载
	 * 执行sql，表的字段名与实体类的属性名一样的情况
	 * @param sql
	 * @param values
	 * @param tClass
	 * @param props
	 * @param <T>
	 * @return
	 */
	public static <T> List<T> querylist(String sql,List<Object> values,Class<T> tClass,List<String> props){
		Map<String,String> fields = new HashMap<>();
		for (String p:props)
			fields.put(p,p);
			return querylist(sql,values,tClass,fields);
	}

	/**
	 * 第二次重载
	 * 执行SQL，实体类的属性名与表的字段名一样的情况
	 * @param sql
	 * @param values
	 * @param tClass
	 * @param <T>
	 * @return
	 */
	public static <T> List<T> querylist(String sql,List<Object> values,Class<T> tClass){
		Map<String,String> fields = new HashMap<>();
		for (Field p:tClass.getDeclaredFields())
			fields.put(p.getName(),p.getName());
		return querylist(sql,values,tClass,fields);
	}

	/**
	 * 执行DQL语句，返回一个结果对象
	 * @param sql
	 * @param values
	 * @param tClass
	 * @param fields
	 * @param <T>
	 * @return
	 */
	public static <T> T queryModel(String sql,List<Object> values,Class<T> tClass,Map<String,String> fields){ // class:用类的描述传递泛型
		Connection conn=null;
		PreparedStatement ps = null;
		ResultSet rs = null;
		try {
			conn = getConnection();
			ps = conn.prepareStatement(sql);
			for (int i = 0;i< values.size();i++)
				ps.setObject(i+1,values.get(i));
			rs = ps.executeQuery();
			if (rs.next()){
				T model = tClass.newInstance(); // 用反射得到T的对象
				for (Map.Entry<String,String> entry:fields.entrySet()){
					Field field = tClass.getDeclaredField(entry.getKey()); // 根据属性名反射出对应的反射对象
					field.setAccessible(true);
					field.set(model,rs.getObject(entry.getValue()));
				}
				return model;
			}
		} catch (SQLException e) {
			e.printStackTrace();
		} catch (InstantiationException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (NoSuchFieldException e) {
			e.printStackTrace();
		} finally {
			close(conn,ps,rs);
		}
		return null;
	}

	/**
	 * 第一次重载
	 * @param sql
	 * @param values
	 * @param tClass
	 * @param props
	 * @param <T>
	 * @return
	 */
	public static <T> T queryModel(String sql,List<Object> values,Class<T> tClass,List<String> props){
		Map<String,String> fields = new HashMap<>();
		for (String p:props)
			fields.put(p,p);
		return queryModel(sql,values,tClass,fields);
	}

	/**
	 * 第二次重载
	 * @param sql
	 * @param values
	 * @param tClass
	 * @param <T>
	 * @return
	 */
	public static <T> T queryModel(String sql,List<Object> values,Class<T> tClass){
		Map<String,String> fields = new HashMap<>();
		for (Field p:tClass.getDeclaredFields())
			fields.put(p.getName(),p.getName());
		return queryModel(sql,values,tClass,fields);
	}

	// 方法重载
	// DML不需要使用结果集
	public static void close(Connection conn, Statement st) {
		close(conn, st, null);
	}

	// 可以用来给DQL关闭
	public static void close(Connection conn, Statement st, ResultSet rs) {
		try {
			if (conn != null) {
				conn.close();
				conn = null;
			}
			if (st != null) {
				st.close();
				st = null;
			}
			if (rs != null) {
				rs.close();
				rs = null;
			}
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}

	/**
	 * 根据查询得到记录条数
	 * @param sql
	 * @param vals
	 * @return
	 */
	public static Integer queryInt(String sql,List<Object> vals){
		Connection conn = null;
		PreparedStatement ps = null;
		try {
			conn = getConnection();
			ps = conn.prepareStatement(sql);
			for (int i = 0;i<vals.size();i++)
				ps.setObject(i+1,vals.get(i));
			ResultSet resultSet = ps.executeQuery();
			if (resultSet.next()){
				return resultSet.getInt(1);
			}
		} catch (SQLException e) {
			e.printStackTrace();
		}finally {
			close(conn,ps);
		}
		return null;
	}

	// 调试
	public static void main(String[] args) throws SQLException {
		Connection conn = JDBCUtil.getConnection();
		System.out.println(conn);
	}
}
